package techstudy;

import static org.junit.Assert.assertNull;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.*;

import org.junit.jupiter.api.Test;

public class MockitoMockSpyDemo {

	public String fun1(String in) {
		System.out.println(in);
		return in;
	}

	public String fun2(String in) {
		System.out.println(in);
		return in;
	}
	
  
	//mock默认不执行原有方法，没有when...thenReturn设置则返回null，除非通过doCallRealMethod设置
	//spy默认执行原有方法，除非通过doReturn..when设置。注意：通过when...thenReturn设置时，设置那次原有方法总是被执行
	static public class UnitTest {

		@Test
		public void mock_without_when() {
			MockitoMockSpyDemo mocked = mock(MockitoMockSpyDemo.class);

			String ret = mocked.fun1("hello");

			assertNull(ret);
		}

		@Test
		public void mock_with_when_thenReturn() {
			MockitoMockSpyDemo mocked = mock(MockitoMockSpyDemo.class);

			when(mocked.fun1("hello")).thenReturn("world");

			String ret = mocked.fun1("hello");

			assertEquals("world", ret);
		}

		@Test
		public void mock_with_doCallRealMethod() {
			MockitoMockSpyDemo mocked = mock(MockitoMockSpyDemo.class);

			doCallRealMethod().when(mocked).fun1("hello");

			assertEquals("hello", mocked.fun1("hello"));
			assertNull(mocked.fun1("world"));
			assertNull(mocked.fun2("hello"));
		}

		@Test
		public void spy_without_when() {
			MockitoMockSpyDemo spied = spy(MockitoMockSpyDemo.class);
			
			//call the real method
			when(spied.fun1("hello")).thenReturn("world");
			
			//donot call the real method
			assertEquals("world", spied.fun1("hello"));
			
			//call the real method
			assertEquals("world", spied.fun1("world"));
			//call the real method
			assertEquals("fun2world", spied.fun1("fun2world"));
		}
		
		@Test
		public void spy_without_doReturn() {
			MockitoMockSpyDemo spied = spy(MockitoMockSpyDemo.class);
			
			//donot call the real method
			doReturn("world").when(spied).fun1("hello");
			
			//donot call the real method
			assertEquals("world", spied.fun1("hello"));
			
			//call the real method
			assertEquals("world", spied.fun1("world"));
			//call the real method
			assertEquals("fun2world", spied.fun1("fun2world"));
		}
		
		@Test
		public void spy_times() {
			MockitoMockSpyDemo spied = spy(MockitoMockSpyDemo.class);
			
			when(spied.fun1("hello")).thenReturn("world");
			
			spied.fun1("hello");
			spied.fun1("hello");
			verify(spied, times(2)).fun1("hello");
			
			spied.fun2("fun2");spied.fun2("fun2");
			verify(spied, atLeastOnce()).fun2("fun2");
			
		}
	}
}
